﻿//using FirstFloor.ModernUI.Windows.Controls;
using KinectLibrary;
using KinectLibrary.Contour;
using KinectLibrary.Curves;
using KinectLibrary.Debug;
using KinectLibrary.DTWGestureRecognition;
using KinectLibrary.Enhancements;
using KinectLibrary.Fingers;
using KinectLibrary.TTS;
using Microsoft.Kinect;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace SLA
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private IKinect kinectDevice;
        private RangeFinder rangeFinder;
        private IContourTracking contourTracking;
        private ICurveDetection curveDetection;
        private IFingerRecognition fingerRecognition;
        private DistanceScanner distanceScanner;
        private IGestureRecognition gestureRecognition;
        private IPrediction prediction;
        private HandEnhancements handEnhancements;
        //private DebugInfo debugInfo;
        private Hand prevHand;
        private List<Articulation> skeleton;
        private Thread debugThread;
        private bool isCapturing;
        private bool isSkeletonReady;
        private Brush foregroundNotification;
        private const float minSkeletonDist = 0.875f;
        //private DebugLog debugWindow;

        private readonly List<JointType> validJoints = new List<JointType>()
        {
            JointType.HipCenter, 
            JointType.Spine, 
            JointType.ShoulderCenter, 
            JointType.Head, 
            JointType.ShoulderLeft, 
            JointType.ElbowLeft, 
            JointType.WristLeft, 
            JointType.HandLeft, 
            JointType.ShoulderRight, 
            JointType.ElbowRight, 
            JointType.WristRight, 
            JointType.HandRight
        };

        private Point? rightHand;
        private Point? leftHand;

        private DateTime captureCountdown = DateTime.Now;
        private DispatcherTimer captureCountdownTimer;
        
        public MainWindow()
        {
            InitializeComponent();
        }
        
        private Canvas getSkeletonCanvas()
        {
            return canvas.Children[0] as Canvas;
        }

        private Canvas getFingersCanvas()
        {
            return canvas.Children[1] as Canvas;
        }
        
        private Canvas getNotificationCanvas()
        {
            return canvas.Children[2] as Canvas;
        }

        public IContourTracking ContourTracking { get { return contourTracking; } }
        public ICurveDetection CurveDetection { get { return curveDetection; } }
        public IFingerRecognition FingerRecognition { get { return fingerRecognition; } }
        public IGestureRecognition GestureRecognition { get { return gestureRecognition; } }
        //public DebugInfo DebugInfo { get { return debugInfo; } }

        private void InitializeDistanceThreshold(int minDepthDistance)
        {
            const int distanceInterval = 150;
            DistanceThreshold = new DistanceThreshold
            {
                MinDistance = minDepthDistance,
                MaxDistance = minDepthDistance + distanceInterval
            };

            //debugInfo.DistanceThreshold = DistanceThreshold;
        }

        private void InitializeDebugInfo()
        {
            //debugInfo.GestureDebugInfo = gestureRecognition as IGestureRecognitionDebug;
        }

        private void CreateEvents()
        {
            kinectDevice.DepthDistanceUpdated += new DepthDistanceEventHandler(kinectDevice_DepthDistanceUpdated);
            kinectDevice.SkeletonReady += new SkeletonEventHandler(kinectDevice_SkeletonReady);
            contourTracking.ContourDataReady += new ContourReady(contourTracking_ContourDataReady);
            fingerRecognition.FingertipLocationsReady += new FingertipPoints(fingerRecognition_FingertipLocationsReady);
            gestureRecognition.GestureRecognized += new GestureReady(gestureRecognition_GestureRecognized);
            gestureRecognition.GestureNotFound += new GestureNotFound(gestureRecognition_GestureNotFound);
            gestureRecognition.GestureRecorded += new GestureRecorded(gestureRecognition_GestureRecorded);
        }
               
        private void kinectDevice_SkeletonReady(Microsoft.Kinect.Skeleton skeleton)
        {
            var canvas = getSkeletonCanvas();
            canvas.Children.Clear();
            
            if (skeleton != null && lblMetros.Text == string.Empty)
            {
                lblMetros.Text = "Mts";
            }
            else if (skeleton == null)
            {
                lblMetros.Text = string.Empty;
            }
            lblDistancia.Text = skeleton != null ? skeleton.Position.Z.ToString("F3") : "N/A";
            if (skeleton != null && skeleton.Position.Z > minSkeletonDist)
            {
                rightHand = GetDisplayPosition(skeleton.Joints.FirstOrDefault(j => j.JointType == JointType.HandRight));
                leftHand = GetDisplayPosition(skeleton.Joints.FirstOrDefault(j => j.JointType == JointType.HandLeft));

                this.skeleton = skeleton.Joints.Where(j => validJoints.Contains(j.JointType)).Select(j =>
                {
                    var pos = GetDisplayPosition(j);
                    j.Position = new SkeletonPoint()
                    {
                        X = (float)pos.X,
                        Y = (float)pos.Y
                    };
                    return Articulation.ConvertFromJoint(j);
                }).ToList();

                isSkeletonReady = true;

                var bodySegment1 = GetBodySegment(skeleton.Joints, JointType.HipCenter, JointType.Spine, JointType.ShoulderCenter, JointType.Head);
                var bodySegment2 = GetBodySegment(skeleton.Joints, JointType.ShoulderCenter, JointType.ShoulderLeft, JointType.ElbowLeft, JointType.WristLeft, JointType.HandLeft);
                var bodySegment3 = GetBodySegment(skeleton.Joints, JointType.ShoulderCenter, JointType.ShoulderRight, JointType.ElbowRight, JointType.WristRight, JointType.HandRight);

                DrawingHelper.DrawPolygon(canvas, bodySegment1, DrawingType.BIG);
                DrawingHelper.DrawPolygon(canvas, bodySegment2, DrawingType.BIG);
                DrawingHelper.DrawPolygon(canvas, bodySegment3, DrawingType.BIG);

                foreach (var segment in bodySegment1)
                {
                    canvas.Children.Add(new Ellipse
                    {
                        Fill = Brushes.YellowGreen,
                        Width = 15,
                        Height = 15,
                        Margin = new Thickness(segment.X - 7.5, segment.Y - 7.5, 0, 0)
                    });
                }

                foreach (var segment in bodySegment2)
                {
                    canvas.Children.Add(new Ellipse
                    {
                        Fill = Brushes.YellowGreen,
                        Width = 15,
                        Height = 15,
                        Margin = new Thickness(segment.X - 7.5, segment.Y - 7.5, 0, 0)
                    });
                }

                foreach (var segment in bodySegment3)
                {
                    canvas.Children.Add(new Ellipse
                    {
                        Fill = Brushes.YellowGreen,
                        Width = 15,
                        Height = 15,
                        Margin = new Thickness(segment.X - 7.5, segment.Y - 7.5, 0, 0)
                    });
                }

                if (DebugInfo.DebugSkeletonDist)
                    Logger.Log("skeletonDist#" + skeleton.Position.Z);
            }
            else
            {
                lblDistancia.Text = "N/A";
                lblMetros.Text = string.Empty;
            }
        }

        private Point GetDisplayPosition(Joint joint)
        {
            float depthX, depthY;
            var pos = kinectDevice.Sensor.MapSkeletonPointToDepth(joint.Position, DepthImageFormat.Resolution320x240Fps30);

            depthX = pos.X;
            depthY = pos.Y;

            int colorX, colorY;

            // Only ImageResolution.Resolution640x480 is supported at this point
            var pos2 = kinectDevice.Sensor.MapSkeletonPointToColor(joint.Position, ColorImageFormat.RgbResolution640x480Fps30);
            colorX = pos2.X;
            colorY = pos2.Y;

            // Map back to skeleton.Width & skeleton.Height
            return DrawingHelper.TransformPoint(this.canvas, colorX, colorY);
        }
               
        private Point[] GetBodySegment(IEnumerable<Joint> joints, params JointType[] ids)
        {
            var points = new Point[ids.Count()];

            int iJoint = 0;
            foreach (JointType t in ids)
            {
                var joint = joints.FirstOrDefault(j => j.JointType == t);
                if (joint != null)
                {
                    points[iJoint] = GetDisplayPosition(joint);
                    iJoint++;
                }
            }

            return points;
        }

        private void kinectDevice_DepthDistanceUpdated(short[] depthDistanceData, int width, int height)
        {
            Width = width;
            Height = height;

            Pixel[] pixelsInRange = rangeFinder.PixelsInRange(depthDistanceData, DistanceThreshold.MinDistance, DistanceThreshold.MaxDistance);

            //debugInfo.RangeData = pixelsInRange;

            contourTracking.StartTracking(pixelsInRange, width, height);
        }


        private void contourTracking_ContourDataReady(IEnumerable<KinectLibrary.Vector> contourPoints, Pixel[] pixels)
        {
            IEnumerable<CurvePoint> curves = curveDetection.FindCurves(contourPoints);

            IEnumerable<Fingertip> points = fingerRecognition.FindFingertipLocations(curves, pixels, Width, Height);
            int fingerCount = ((IList<Fingertip>)points).Count;

            if (UpdateDepthDistaceThreshold)
            {
                AutoscanForDistanceThreshold(fingerCount);
                return; // Dont do anything else while scan is in progress.
            }
        }

        private void AutoscanForDistanceThreshold(int fingerCount)
        {
            DistanceThreshold newDistanceThreshold;

            bool scanFinished = distanceScanner.TwoHandScan(fingerCount, DistanceThreshold, out newDistanceThreshold);
            DistanceThreshold = newDistanceThreshold;

            UpdateDepthDistaceThreshold = !scanFinished;

            //debugInfo.AutoscanInProgress = UpdateDepthDistaceThreshold;
            //debugInfo.DistanceThreshold = DistanceThreshold;
        }

        private void fingerRecognition_FingertipLocationsReady(IEnumerable<Fingertip> points)
        {
                var canvas = getFingersCanvas();
                canvas.Children.Clear();

                /*if (true/*taskHandInconsitencies == null && taskRecognizing == null ||
                    (taskHandInconsitencies != null && !taskHandInconsitencies.IsCompleted &&
                    taskRecognizing != null && !taskRecognizing.IsCompleted))
                {*/
                if (isSkeletonReady)
                {
                    var fingertips = new List<Fingertip>(points);

                    /*var canvas = getNotificationCanvas();
                    canvas.Children.Clear();
                    canvas.Children.Add(new TextBlock()
                    {
                        Margin = new Thickness(5, 5, 5, 5),
                        FontSize = 18,
                        Text = points.Count().ToString()
                    });*/

                    /*if (fingertips.Count > Hand.MaxFingers)
                    {
                        var switcher = true;
                        var length = fingertips.Count - Hand.MaxFingers;
                        for (int i = 0; i < length; i++)
                        {
                            if (switcher)
                            {
                                switcher = false;
                                fingertips.RemoveAt(0);
                            }
                            else
                            {
                                switcher = true;
                                fingertips.RemoveAt(fingertips.Count - 1);
                            }
                        }*/
                    /*fingertips.RemoveAt(0);
                    if (fingertips.Count > Hand.MaxFingers)
                    {
                        fingertips.RemoveAt(fingertips.Count-1);
                    }*/
                    /*var fingersNumberCanvas = getFingersNumberCanvas();
                    fingersNumberCanvas.Children.Clear();
                    fingersNumberCanvas.Children.Add(new TextBlock()
                                {
                                    Margin = new Thickness(5, 28, 5, 5),
                                    FontSize = 18,
                                    Text = fingertips.Count().ToString()
                                });*/
                    //}

                    Hand currentHand = new Hand(fingertips.Take(Hand.MaxFingers));

                    if (EnableSmoothing && prevHand != null)
                    {
                        /*Task.Run(() => currentHand = */
                        Smoothing.ExponentialSmoothing(currentHand, prevHand, SmoothingFactor);//);
                        //Smoothing.ExponentialSmoothing(currentHand, prevHand, SmoothingFactor);
                    }
                    if (PreventHandInconsitencies)
                    {
                        handEnhancements.PreventHandIncosistency(currentHand, skeleton);
                    }
                    else if (gestureRecognition.Recognizing || gestureRecognition.Recording)
                    {
                        /*if (gestureRecognition.Recognizing)
                        {
                            Task.WaitAll();
                        }*/
                        var frame = new KinectLibrary.Frame(new List<Hand>(Hand.MaxHands)
                        {
                            currentHand.Clone() //<cambio>
                        }, skeleton.Clone()); //
                        gestureRecognition.AnalyzeFrame(frame);
                    }

                    //debugInfo.FoundHandInconsistencies = handEnhancements.FixedInconsistencies;

                    //debugInfo.FingertipLocationsReadyCounter++;

                    /*var list = new List<int>();
                    int i = 0;
                    foreach (var children in canvas.Children)
                    {
                        if (children is Ellipse && (children as Ellipse).Fill == Brushes.GreenYellow)
                        {
                            list.Add(i);
                        }
                        i++;
                    }
                    foreach (var item in list)
                    {
                        if (item >= 0 && item < canvas.Children.Count)
                        {
                            canvas.Children.RemoveAt(item);
                        }
                    }*/
                    if (isCapturing)
                    {
                        if (!gestureRecognition.IsGestureStreamSaturated)
                        {
                            lblEstado.Text = "Cuadro " + gestureRecognition.GestureStreamFrameCount;
                        }
                        else
                        {
                            gestureRecognition.StopRecording();
                            isCapturing = false;
                            //gestureRecognition.SaveGesturesToFile("prueba.txt");
                        }
                        //Margin="5" TextWrapping="Wrap" FontSize="16"
                    }

                    foreach (var finger in currentHand.Fingers)
                    {
                        if (finger.Position.X != Hand.FingerNotFound.X)
                        {
                            var cords = DrawingHelper.TransformPoint(this.canvas, (int)finger.Position.X, (int)finger.Position.Y);

                            var distRight = double.PositiveInfinity;
                            var distLeft = double.PositiveInfinity;

                            if (rightHand.HasValue)
                            {
                                distRight = MathHelper.GetDistance(cords.X, rightHand.Value.X, cords.Y, rightHand.Value.Y);
                            }
                            if (leftHand.HasValue)
                            {
                                distLeft = MathHelper.GetDistance(cords.X, leftHand.Value.X, cords.Y, leftHand.Value.Y);
                            }

                            if (distRight < distLeft)
                            {
                                if (rightHand.HasValue)
                                {
                                    canvas.Children.Add(new Line
                                    {
                                        Stroke = Brushes.Green,
                                        StrokeThickness = 2.5,
                                        X1 = cords.X,
                                        Y1 = cords.Y,
                                        X2 = rightHand.Value.X,
                                        Y2 = rightHand.Value.Y
                                    });
                                }
                            }
                            else if (distRight > distLeft)
                            {
                                if (leftHand.HasValue)
                                {
                                    canvas.Children.Add(new Line
                                    {
                                        Stroke = Brushes.Green,
                                        StrokeThickness = 2.5,
                                        X1 = cords.X,
                                        Y1 = cords.Y,
                                        X2 = leftHand.Value.X,
                                        Y2 = leftHand.Value.Y
                                    });
                                }
                            }

                            canvas.Children.Add(new Ellipse
                            {
                                Fill = Brushes.GreenYellow,
                                Width = 10,
                                Height = 10,
                                Margin = new Thickness(cords.X - 5, cords.Y - 5, 0, 0)
                            });

                            /*var fingerName = String.Empty;

                            if (finger == currentHand.Thumb)
                            {
                                fingerName = "Pulgar";
                            }
                            else if (finger == currentHand.IndexFinger)
                            {
                                fingerName = "Indice";
                            }
                            else if (finger == currentHand.MiddleFinger)
                            {
                                fingerName = "Medio";
                            }
                            else if (finger == currentHand.RingFinger)
                            {
                                fingerName = "Anillo";
                            }
                            else if (finger == currentHand.LittleFinger)
                            {
                                fingerName = "Menique";
                            }

                            canvas.Children.Add(new TextBlock()
                            {
                                Margin = new Thickness(cords.X - 10, cords.Y - 10, 0, 0),
                                FontSize = 10,
                                Text = fingerName
                            });*/
                        }
                    }
                    //}

                    prevHand = currentHand;
                    isSkeletonReady = false;
                    //}
                }
        }

        private void gestureRecognition_GestureRecognized(Gesture recognizedGesture)
        {
            this.Dispatcher.Invoke((Action)(() =>
            {
                lock (this.canvas)
                {
                    var canvas = getNotificationCanvas();
                    canvas.Children.Clear();
                    //<TextBlock x:Name="lblEstado" Margin="5" TextWrapping="Wrap" FontSize="14"/>
                    canvas.Children.Add(new TextBlock()
                    {
                        Margin = new Thickness(20, 10, 10, 10),
                        FontSize = 60,
                        Text = recognizedGesture.Speech,
                        Foreground = foregroundNotification
                    });

                    //debugInfo.GestureRecognized = true;
                    lblEstado.Text = "Gesto reconocido";//+recognizedGesture.Name;
                    SpeechSpeaker.SayIt(recognizedGesture.Speech);
                }
            }));
            //Thread.Sleep(1000);
        }

        private void gestureRecognition_GestureNotFound()
        {
            this.Dispatcher.Invoke((Action)(() =>
            {
                lock (this.canvas)
                {
                    getNotificationCanvas().Children.Clear();
                    /*if (lblEstado.Text == "Gesture recognized")
                    {*/
                    lblEstado.Text = String.Empty;
                }
            }));
            //}
        }

        private void gestureRecognition_GestureRecorded(Gesture recordedGesture)
        {
            lblEstado.Text = "Gesto grabado";
            var item = cmbGestos.SelectedItem as ComboBoxItem;
            recordedGesture.Name = item.Name.ToString();
            recordedGesture.Speech = item.Tag.ToString();
            gestureRecognition.StoreGesture(recordedGesture);
            DrawGesture(recordedGesture);
            //gestureRecognition.SaveGesturesToFile("prueba.txt");
            gestureRecognition.StartRecognizer();
        }

        public double SmoothingFactor { get; set; }

        public bool EnableSmoothing { get; set; }

        public bool PreventHandInconsitencies { get; set; }
        private DistanceThreshold DistanceThreshold { get; set; }
        public bool UpdateDepthDistaceThreshold { get; set; }

        private new int Height { get; set; }
        private new int Width { get; set; }

        private void btnCapturar_Click(object sender, RoutedEventArgs e)
        {
            if (cmbGestos.SelectionBoxItem != null && !String.IsNullOrWhiteSpace(cmbGestos.SelectionBoxItem.ToString()))
            {
                captureCountdown = DateTime.Now.AddSeconds(Convert.ToInt32(Math.Ceiling(sdrSegundos.Value)));

                captureCountdownTimer = new DispatcherTimer();
                captureCountdownTimer.Tick += new EventHandler(CaptureCountdown);
                captureCountdownTimer.Interval = new TimeSpan(0, 0, 1);
                captureCountdownTimer.Start();
                gestureRecognition.StopRecognizer();
            }
        }

        private void btnResetList_Click(object sender, RoutedEventArgs e)
        {
            if (gestureRecognition != null)
            {
                cmbGestos.Items.Clear();
                gestureRecognition.Gestures.Clear();
            }
            canvasFrame0.Children.Clear();
            canvasFrame19.Children.Clear();
            canvasFrame38.Children.Clear();
        }

        private void CaptureCountdown(object sender, EventArgs e)
        {
            if (sender == captureCountdownTimer)
            {
                if (DateTime.Now < captureCountdown)
                {
                    lblEstado.Text = "Espera " + ((captureCountdown - DateTime.Now).Seconds + 1) + " segundos";
                }
                else
                {
                    captureCountdownTimer.Stop();
                    lblEstado.Text = "Grabando gesto";
                    StartCapture();
                }
            }
        }

        private void StartCapture()
        {
            gestureRecognition.StartRecording();
            isCapturing = true;
            lblEstado.Text = "Grabando gesto " + (cmbGestos.SelectedItem as ComboBoxItem).Name.ToString();
        }

        private void btnGuardar_Click(object sender, RoutedEventArgs e)
        {
            var dialog = new SaveFileDialog();
            dialog.InitialDirectory = Convert.ToString(Environment.SpecialFolder.MyDocuments);
            dialog.Filter = "Text Files (*.txt)|*.txt";
            dialog.FilterIndex = 1;

            var result = dialog.ShowDialog();

            if (result.HasValue && result.Value)
            {
                gestureRecognition.SaveGesturesToFile(dialog.FileName);
                lblEstado.Text = "Gestos guardados";// to" + dialog.FileName;
            } 
        }

        private void btnCargar_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var dialog = new OpenFileDialog();
                dialog.Filter = "Text Files (*.txt)|*.txt";
                dialog.FilterIndex = 1;

                var result = dialog.ShowDialog();

                if (result.HasValue && result.Value)
                {
                    gestureRecognition.LoadGesturesFromFile(dialog.FileName);
                    cmbGestos.Items.Clear();
                    foreach (var gesture in gestureRecognition.Gestures)
                    {
                        cmbGestos.Items.Add(new ComboBoxItem()
                        {
                            Name = gesture.Name,
                            Tag = gesture.Speech,
                            Content = gesture.Name
                        });
                    }
                    lblEstado.Text = "Gestos cargados";
                    gestureRecognition.StartRecognizer();
                }
            }
            catch
            {
                MessageBox.Show("Error al intentar cargar el archivo!");
            }
        }

        private void sdrDelta_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (gestureRecognition != null)
            {
                gestureRecognition.RecognitionFactor = Convert.ToInt32(Math.Ceiling(sdrDelta.Value));
            }
        }

        /*private void sdrWords_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            SpeechSpeaker.WordsBeforeSpeak = Convert.ToInt32(Math.Ceiling(sdrWords.Value));
        }*/

        private void sdrAngle_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (kinectDevice != null)
            {
                try
                {
                    kinectDevice.Sensor.ElevationAngle = Convert.ToInt32(Math.Ceiling(sdrAngle.Value));
                }
                catch
                {
                }
            }
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            StartApp();
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
            Dispatcher.UnhandledException += Dispatcher_UnhandledException;
            Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;
            TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
        }

        void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
        {
            MessageBox.Show(e.Exception.InnerException == null ? e.Exception.ToString() : e.Exception.InnerException.ToString() + "\n\n" +
                            e.Exception.StackTrace.ToString());
        }

        void Current_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            MessageBox.Show(e.Exception.InnerException == null ? e.Exception.ToString() : e.Exception.InnerException.ToString() + "\n\n" +
                            e.Exception.StackTrace.ToString());
        }

        void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            MessageBox.Show(e.Exception.InnerException == null ? e.Exception.ToString() : e.Exception.InnerException.ToString() + "\n\n" +
                            e.Exception.StackTrace.ToString());
        }

        void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            MessageBox.Show(e.ExceptionObject == null ? string.Empty : e.ExceptionObject.ToString() + "\n\n" +
                            e.ToString());
        }

        private void StartApp()
        {
            try
            {
                var canvasCenter = new Canvas();
                var x = canvas.ActualWidth / 7;
                var y = canvas.ActualHeight / 7;
                canvasCenter.Children.Add(new Line()
                {
                    X1 = x * 3,
                    X2 = x * 4,
                    Y1 = canvas.ActualHeight / 2,
                    Y2 = canvas.ActualHeight / 2,
                    StrokeThickness = 2,
                    Stroke = Brushes.Red
                });
                canvasCenter.Children.Add(new Line()
                {
                    X1 = canvas.ActualWidth / 2,
                    X2 = canvas.ActualWidth / 2,
                    Y1 = y * 3,
                    Y2 = y * 4,
                    StrokeThickness = 2,
                    Stroke = Brushes.Red
                });
                canvas.Children.Add(new Canvas()); //Skeleton
                canvas.Children.Add(new Canvas()); //Fingers
                canvas.Children.Add(new Canvas()); //Notifications  
                canvas.Children.Add(canvasCenter);
                
                EnableSmoothing = true;
                PreventHandInconsitencies = true;
                SmoothingFactor = 0.47;

                lblDistancia.Text = "N/A";
                lblMetros.Text = string.Empty;

                // Distances in millimeter.
                const int minDepthDistance = 800; // The minimum distance where the Kinect for Xbox 360 can detect objects.
                const int maxDepthDistance = 4000;

                var converter = new System.Windows.Media.BrushConverter();
                foregroundNotification = (Brush)converter.ConvertFromString("#FF007EFF");

                this.kinectDevice = new Kinect();
                var angle = (kinectDevice.Sensor.MaxElevationAngle + kinectDevice.Sensor.MinElevationAngle) / 2;
                kinectDevice.Sensor.ElevationAngle = angle;
                sdrAngle.Value = angle;
                sdrAngle.Minimum = kinectDevice.Sensor.MinElevationAngle;
                sdrAngle.Maximum = kinectDevice.Sensor.MaxElevationAngle;
                kinectRegion.KinectSensor = kinectDevice.Sensor;
                var sensorDepthRange = new DistanceThreshold { MinDistance = minDepthDistance, MaxDistance = maxDepthDistance };
                rangeFinder = new RangeFinder();
                contourTracking = new ContourTracking();
                curveDetection = new CurveDetection();
                fingerRecognition = new FingerRecognition(rangeFinder);
                distanceScanner = new DistanceScanner(sensorDepthRange);
                gestureRecognition = new GestureRecognition();
                SpeechSpeaker.InitializeSpeechSpeaker();
                //sdrWords.Value = SpeechSpeaker.WordsBeforeSpeak;
                sdrSegundos.Value = 10;
                sdrDelta.Value = 7;
                prediction = new Prediction();
                handEnhancements = new HandEnhancements(prediction, gestureRecognition);
                //debugInfo = new DebugInfo();
                skeleton = null;
                rightHand = null;
                leftHand = null;
                isCapturing = false;
                
                InitializeDistanceThreshold(minDepthDistance);
                InitializeDebugInfo();
                CreateEvents();
            }
            catch (ArgumentOutOfRangeException)
            {
                MessageBox.Show("El dispositivo Kinect no se encuentra conectado");
                this.Close();
            }
            catch (Exception e)
            {
                MessageBox.Show("No se pudo comunicar con el dispositivo Kinect conectado");
                this.Close();
            }
        }

        private void MainWindow_Closed(object sender, EventArgs e)
        {
            if (this.kinectDevice != null)
            {
                this.kinectDevice.SkeletonReady -= kinectDevice_SkeletonReady;
                this.kinectDevice.Stop();
                if (this.debugThread != null)
                {
                    this.debugThread.Abort();
                    //this.debugWindow.Close();
                }
            }
        }

        private void btnDebug_Click(object sender, RoutedEventArgs e)
        {
            /*var threadId = System.Threading.Thread.CurrentThread.ManagedThreadId.ToString();

            var fingersNumberCanvas = getFingersNumberCanvas();
            fingersNumberCanvas.Children.Clear();
            fingersNumberCanvas.Children.Add(new TextBlock()
                        {
                            Margin = new Thickness(5, 28, 5, 5),
                            FontSize = 18,
                            Text = threadId
                        });*/
            debugThread = new Thread(delegate()
                {
                    var debugWindow = new DebugLog();
                    debugWindow.Show();

                    System.Windows.Threading.Dispatcher.Run();
                });

            debugThread.SetApartmentState(ApartmentState.STA);
            debugThread.Start();
        }

        private void btnAdd_Click(object sender, RoutedEventArgs e)
        {
            /*if (chkRemover.IsChecked.HasValue && chkRemover.IsChecked.Value)
            {
                var item = cmbGestos.SelectedItem as ComboBoxItem;
                cmbGestos.Items.Remove(item);
                var gesture = gestureRecognition.Gestures.FirstOrDefault(g => g.Name == item.Name.ToString());
                if (gesture != null)
                {
                    gestureRecognition.Gestures.Remove(gesture);
                }
            }
            else
            {*/     
                var addWindow = new GestureWindow(cmbGestos);
                addWindow.Show();
            //}
        }

        private void cmbGestos_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var selectedItem = (sender as ComboBox).SelectedItem;
            if (selectedItem != null)
            {
                var gestureName = (selectedItem as ComboBoxItem).Content.ToString();
                if (!String.IsNullOrWhiteSpace(gestureName))
                {
                    var gesture = gestureRecognition.Gestures.FirstOrDefault(g => g.Name == gestureName);
                    if (gesture != null)
                    {
                        DrawGesture(gesture);
                    }
                    else
                    {
                        canvasFrame0.Children.Clear();
                        canvasFrame19.Children.Clear();
                        canvasFrame38.Children.Clear();
                    }
                }
            }            
        }

        private void DrawGesture(Gesture gesture)
        {
            DrawingHelper.DrawFrame(gesture.Frames[0], canvasFrame0, DrawingType.SMALL);
            DrawingHelper.DrawFrame(gesture.Frames[19], canvasFrame19, DrawingType.SMALL);
            DrawingHelper.DrawFrame(gesture.Frames[38], canvasFrame38, DrawingType.SMALL);
        }

        private void MainWindow_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape)
            {
                this.Close();
            }
        }

        private void chkRepetirTexto_Checked(object sender, RoutedEventArgs e)
        {
            lock (this)
            {
                SpeechSpeaker.RepeatSpeech = true;
            }
        }

        private void chkRepetirTexto_Unchecked(object sender, RoutedEventArgs e)
        {
            lock (this)
            {
                SpeechSpeaker.RepeatSpeech = false;
            }
        }

        private void btnPlay_Click(object sender, RoutedEventArgs e)
        {
            if (gestureRecognition != null && cmbGestos.SelectedItem != null)
            {
                //Microsoft.Expression.Interactivity.Core.ExtendedVisualStateManager.GoToElementState(this.kinectRegion, "Play", true);
                SpeechSpeaker.EnableSpeech = false;
                var play = new PlayWindow(kinectRegion.KinectSensor, gestureRecognition.Gestures, (cmbGestos.SelectedItem as ComboBoxItem).Name.ToString());
                play.Closed += play_Closed;
                play.Show();
            }
        }

        void play_Closed(object sender, EventArgs e)
        {
            SpeechSpeaker.EnableSpeech = true;
        }

        private void btnSwitch_Click(object sender, RoutedEventArgs e)
        {
            if (imgRecord.Visibility == Visibility.Visible)
            {
                imgRecord.Visibility = Visibility.Collapsed;
                imgRecognize.Visibility = Visibility.Visible;
                kinectRegion.KinectSensor = null;
            }
            else if (imgRecognize.Visibility == Visibility.Visible)
            {
                imgRecord.Visibility = Visibility.Visible;
                imgRecognize.Visibility = Visibility.Collapsed;
                if (kinectDevice != null)
                {
                    kinectRegion.KinectSensor = kinectDevice.Sensor;
                }
            }
        }
    }
}
